﻿using ApplicationBase.Core.Model;
using AutoMapper;
using IdentityService.Domain.Aggregates.RoleAggregate;
using IdentityService.Infrastructure;
using IdentityService.Infrastructure.Dtos;
using Microsoft.EntityFrameworkCore;

namespace IdentityService.Application.QueryService
{
    public interface IRoleQueryService
    {
        Task<List<Role>> GetAllAsync();
        Task<Role?> GetDetailByIdAsync(long id);
        Task<TableData<UserAccountDto>> FindMemberOfRoleAsync(FindMemberOfRoleQueryRequest request);
    }
    public class RoleQueryService : IRoleQueryService
    {
        private readonly AppIdentityDbContext _dbContext;
        private readonly IMapper _mapper;
        public RoleQueryService(AppIdentityDbContext dbContext, IMapper mapper)
            => (_dbContext, _mapper) = (dbContext, mapper);

        public async Task<List<Role>> GetAllAsync()
        {
            return await _dbContext.Role.AsNoTracking().ToListAsync();
        }

        public async Task<Role?> GetDetailByIdAsync(long id)
        {
            return await _dbContext.Role.AsNoTracking().Include(it => it.Permits).FirstOrDefaultAsync(it => it.Id == id);
        }

        public async Task<TableData<UserAccountDto>> FindMemberOfRoleAsync(FindMemberOfRoleQueryRequest request)
        {
            if (request.PageInfo == null) throw new ArgumentNullException("PageInfo");

            var role = await _dbContext.Role.AsNoTracking()
                .Include(it => it.UserAccounts
                    .Where(it => string.IsNullOrEmpty(request.KeyWords)
                        || it.UserName.Contains(request.KeyWords) || it.Id.ToString() == request.KeyWords
                        || (string.IsNullOrEmpty(it.PhoneNumber) && it.PhoneNumber!.Contains(request.KeyWords))
                        || (string.IsNullOrEmpty(it.Email) && it.Email!.Contains(request.KeyWords)))
                    .Skip(request.PageInfo.GetStartIndex())
                    .Take(request.PageInfo.Size))
                .FirstOrDefaultAsync(it => it.Id == request.RoleId);
            if(role == null)
            {
                return new TableData<UserAccountDto>
                {
                    TotalCount = 0,
                    Data = new List<UserAccountDto>()
                };
            }

            var dtoList = _mapper.Map<List<UserAccountDto>>(role.UserAccounts);
            var totalCount = await _dbContext.UserAccount.AsNoTracking().Include(it => it.Roles)
                .Where(it => it.Roles.Any(r => r.Id == request.RoleId))
                .Where(it => string.IsNullOrEmpty(request.KeyWords)
                    || it.UserName.Contains(request.KeyWords) || it.Id.ToString() == request.KeyWords
                    || (string.IsNullOrEmpty(it.PhoneNumber) && it.PhoneNumber!.Contains(request.KeyWords))
                    || (string.IsNullOrEmpty(it.Email) && it.Email!.Contains(request.KeyWords)))
                .CountAsync();   
            return new TableData<UserAccountDto>
            {
                TotalCount = totalCount,
                Data = dtoList
            };
        }
    }

    public class FindMemberOfRoleQueryRequest
    {
        public string? KeyWords { get; set; }
        public long RoleId { get; set; }
        public PageInfo? PageInfo { get; set; }
    }
}
